package com.miao.test.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.miao.test.client.ClientTest;
import com.miao.test.client.WebSocketClientHandler;
import com.miao.test.common.Message;
import com.miao.test.common.enums.Command;
import com.miao.test.model.AuthRequestModel;
import com.miao.test.model.AuthResponseModel;
import com.miao.test.model.HeartBeatModel;
import com.miao.test.model.P2PRequestModel;
import com.miao.test.support.MetricsManager;
import com.miao.test.support.MetricsStatistics;
import com.miao.test.support.SocketMetrics;
import com.miao.test.support.SocketUtil;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Auther: miaoguoxin
 * @Date: 2021/5/17 15:58
 * @Description:
 */
@RestController
@RequestMapping("pressure")
@Slf4j
public class PressureTestController {
    private static Map<Channel, List<Message>> messageMap = new ConcurrentHashMap<>();
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ClientTest clientTest;

    private ExecutorService executorService = Executors.newFixedThreadPool(30);

    @RequestMapping("login")
    public void login(String username, String deviceNumber) {
        Set<String> keys = redisTemplate.keys("web_login_session:*");
        for (Channel channel : ClientTest.channelList) {
            List<String> listKeys = new ArrayList<>(keys);
            String key = RandomUtil.randomEle(listKeys);
            String json = redisTemplate.opsForValue().get(key);
            JSONObject jsonObject = JSON.parseObject(json);

            AuthRequestModel.AuthRequest request = AuthRequestModel.AuthRequest.newBuilder()
                    .setDeviceNumber(jsonObject.getString("deviceNumber"))
                    .setUsername(jsonObject.getString("sessionId"))
                    .setPassword("")
                    .build();
            Message message = Message.writeRequest(1, 0, Command.AUTH.getCode(), request.toByteArray());
            BinaryWebSocketFrame binaryWebSocketFrame = new BinaryWebSocketFrame(message.getByteBuf());
            channel.writeAndFlush(binaryWebSocketFrame);
            //clientTest.sendMsg(message);
        }
    }

    @RequestMapping("getMsgId")
    public void getMsgId() {
        for (Map.Entry<Channel, AuthResponseModel.AuthResponse> entry : WebSocketClientHandler.userInfos.entrySet()) {
            Channel channel = entry.getKey();
            HeartBeatModel.Heartbeat heartbeat = HeartBeatModel.Heartbeat.newBuilder()
                    .setTimestamp(System.currentTimeMillis())
                    .build();
            for (int i = 0; i < 5; i++) {
                executorService.execute(() -> {
                    int index = 300;
                    while (index > 0) {
                        Message message = Message.writeRequest(1, 0, Command.GENERATE_ID.getCode(), heartbeat.toByteArray());
                        BinaryWebSocketFrame binaryWebSocketFrame = new BinaryWebSocketFrame(message.getByteBuf());
                        channel.writeAndFlush(binaryWebSocketFrame);
                        index--;
                    }
                });
            }
        }
    }

    @PostMapping("p2p")
    public void sendP2p(Long toUserId, String nickname, String avatar) {
        SocketUtil.listenerMap.clear();
        MetricsManager.clear();
        messageMap.clear();
        // num.set(0);
        for (Map.Entry<Channel, AuthResponseModel.AuthResponse> entry : WebSocketClientHandler.userInfos.entrySet()) {
            Channel channel = entry.getKey();
            AuthResponseModel.AuthResponse userInfo = entry.getValue();
            P2PRequestModel.P2PRequest request = P2PRequestModel.P2PRequest.newBuilder()
                    .setFromUserId(Long.parseLong(userInfo.getUserId()))
                    .setFromUserNickname(userInfo.getNickname())
                    .setFromUserAvatar(userInfo.getAvatar())
                    .setFromRoutingKey(userInfo.getRoutingKey())
                    .setToUserId(toUserId)
                    .setToUserAvatar(avatar)
                    .setToUserNickname(nickname)
                    .setMessage("123")
                    .setMediaType(1)
                    .build();
            int index = 200;
            while (index > 0) {
                long msgId = IdUtil.getSnowflake(1, 1).nextId();
                Message message = Message.writeRequest(1, msgId, Command.P2P_SENDER.getCode(), request.toByteArray());
                List<Message> messages = messageMap.get(channel);
                if (messages == null) {
                    messages = new ArrayList<>(index);
                    messageMap.put(channel, messages);
                }
                messages.add(message);
                index--;
            }
        }
        for (Map.Entry<Channel, List<Message>> entry : messageMap.entrySet()) {
            for (Message message : entry.getValue()) {
                SocketMetrics socketMetrics = new SocketMetrics();
                MetricsManager.addMetrics(socketMetrics);
                SocketUtil.write(entry.getKey(), message, respMsg -> socketMetrics.setRespStamp(System.currentTimeMillis()));
            }
        }
    }


    @RequestMapping("conn")
    public void conn(Integer num) {
        for (int i = 0; i < num; i++) {
            new Thread(() -> clientTest.ConnWebSocketServer("ws://localhost:8585/chat"))
                    .start();
        }
    }

    @GetMapping("metrics")
    public MetricsStatistics metrics() {
        return MetricsManager.statistics();
    }
}
